package com.seadragon.app.ksr.loader;

import static com.seadragon.app.ksr.model.KsrConstants.gf;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.seadragon.app.ksr.model.SHPFileRecord;
import com.seadragon.app.ksr.model.shape.PolygonShape;
import com.seadragon.app.ksr.model.tiger.State;
import com.seadragon.app.ksr.util.FileUtils;
import com.seadragon.app.ksr.util.IndexManager;
import com.seadragon.app.ksr.util.tiger.DBFFileReader;
import com.seadragon.app.ksr.util.tiger.SHPFileReader;
import com.vividsolutions.jts.geom.Polygon;


@Component("stateLoader")
public class StateLoader {

	private static Logger logger = LoggerFactory.getLogger(StateLoader.class);
	private static final String SHP_FILE_EXTENSION = ".shp";
	private static final String DBF_FILE_EXTENSION = ".dbf";
	private static final String WORK_FOLDER = "work";
	private DBFFileReader dbfFileReader;
	private SHPFileReader shpFileReader;
	@Autowired
	private IndexManager indexManager;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ApplicationContext appCtx = new ClassPathXmlApplicationContext("ksr-application-context-sa-postgres.xml");
		if (args == null || args.length != 1) {
			logger.error("Usage: StateLoader state_file_directory");
		}
		StateLoader loader = (StateLoader) appCtx.getBean("stateLoader");
		logger.debug("Start to load " + args[0]);
		loader.index(args[0]);
		 ((AbstractApplicationContext)appCtx).close();
	}
	
	public void index(String directory){
		byte[] buffer = new byte[1024];
		File file = new File(directory);
		if (!file.exists()) {
			logger.error("File doesn't exist: " + directory);
			return;
		}
		if (!file.isDirectory()) {
			logger.error("This is not a directory: " + directory);
			return;
		}
		File[] files = file.listFiles();
		File workFolder = new File(WORK_FOLDER);
		if (workFolder.exists()) {
			for (File f : workFolder.listFiles()) {
				f.delete();
			}
		} else {
			workFolder.mkdir();
		}

		for (int i = 0; i < files.length; i++) {
			try {
				ZipInputStream zis = new ZipInputStream(new FileInputStream(files[i]));
				// get the zipped file list entry
				ZipEntry ze = zis.getNextEntry();
				// All the files have the same base name
				String fileName = null;
				while (ze != null) {
					fileName = ze.getName();
					File newFile = new File(workFolder + File.separator + fileName);

//					System.out.println("file unzip : " + newFile.getAbsoluteFile());

					// create all non exists folders
					// else you will hit FileNotFoundException for compressed
					// folder
					new File(newFile.getParent()).mkdirs();

					FileOutputStream fos = new FileOutputStream(newFile);

					int len;
					while ((len = zis.read(buffer)) > 0) {
						fos.write(buffer, 0, len);
					}
					fos.close();
					ze = zis.getNextEntry();
				}
				zis.closeEntry();
				zis.close();
				load(workFolder, FileUtils.getBaseName(fileName));
			} catch (FileNotFoundException ex) {
				logger.error(ex.getMessage(), ex);
			} catch (IOException ex) {
				logger.error(ex.getMessage(), ex);
			}
		}
	}

	 @Transactional
	 public void load(File directory, String baseName) throws FileNotFoundException, IOException {
		dbfFileReader = new DBFFileReader(new File(directory + File.separator + baseName + DBF_FILE_EXTENSION));
		shpFileReader = new SHPFileReader(new File(directory + File.separator + baseName + SHP_FILE_EXTENSION));
		logger.info("Processing " + directory + File.separator + baseName + DBF_FILE_EXTENSION);
		List<State> states = new ArrayList<State>();
		while (dbfFileReader.hasNext() && shpFileReader.hasNext()) {
			List<Object> dbfRecord = dbfFileReader.next();
			SHPFileRecord shpRecord = shpFileReader.next();
			int index = 2;
			State state = new State();
			state.setGeoid((String) dbfRecord.get(index));
			index += 2;
			state.setGeoid((String) dbfRecord.get(index));
			index++;
			state.setStusps((String) dbfRecord.get(index++));
			state.setName((String) dbfRecord.get(index));
			index += 3;
			state.setFuncStat((String)dbfRecord.get(index));
			index += 3;
			Polygon[] polygons = new Polygon[shpRecord.getRecordContent().getNumOfParts()];
			PolygonShape ps = (PolygonShape)shpRecord.getRecordContent();

			for(int i = 0; i < polygons.length; i++){
				if(i == polygons.length - 1){
					polygons[i] = gf.createPolygon(Arrays.copyOfRange(ps.getPoints(), shpRecord.getRecordContent().getParts()[i], ps.getPoints().length));
				}else{
					polygons[i] = gf.createPolygon(Arrays.copyOfRange(ps.getPoints(), shpRecord.getRecordContent().getParts()[i], shpRecord.getRecordContent().getParts()[i+1]));
				}
				if(!polygons[i].isSimple()){
					polygons[i].normalize();
				}
				if(!polygons[i].isValid()){
					polygons[i].normalize();
				}
			}
			state.setGeom(gf.createMultiPolygon(polygons));
			states.add(state);
		}
		dbfFileReader.close();
		shpFileReader.close();
		int index = 0; 
		for(State state : states){
			logger.info(index++ + "");
			try{
				indexManager.insertDocument(state);
			}catch(Exception ex){
				logger.error(ex.getMessage(), ex);
			}
		}
//		try{
//			indexManager.insertBulkStateDocuments(states);
//		}catch(Exception ex){
//			logger.error(ex.getMessage(), ex);
//		}
	}
}
